﻿
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using SDFL.Helper;
using SDFL.Native;

namespace GetHandlesAPP
{
    public partial class ProcessHandlesFrm : Form
    {
        Process selectedProcess = null;
        IntPtr selectedProcessHwnd = IntPtr.Zero;
        string selectedHandleStr = string.Empty;
        List<NativeMethods.SYSTEM_HANDLE_INFORMATION> lstHandles = null;


        public ProcessHandlesFrm()
        {
            InitializeComponent();
        }        

        private void Form1_Load(object sender, EventArgs e)
        {
            IEnumerable<Process> pses = Process.GetProcesses().OrderBy(p=>p.ProcessName);

            ProcessLable.Text = string.Format("Process count: {0}", pses.Count());

            foreach (Process ps in pses)
            {
                processesListBox.Items.Add(String.Format("[Process:{0}]      [ID:{1}]      [HandleCount:{2}]", ps.ProcessName, ps.Id, ps.HandleCount));                
            }
        }

        private void processesListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            HandlesOfProcessListBox.Items.Clear();

            string processStr = processesListBox.SelectedItem.ToString();

            Regex pattern = new Regex(@"\[Process:(?<Name>\w+)\]\s+\[ID:(?<ID>\d+)");
            Match matchProcess = pattern.Match(processStr);
            string processName = matchProcess.Groups["Name"].Value;
            string id = matchProcess.Groups["ID"].Value;

            Process[] pses = Process.GetProcessesByName(processName);           

            foreach (Process ps in pses)
            {
                if (ps.Id == int.Parse(id))
                {
                    selectedProcess = ps;
                    selectedProcessHwnd = NativeMethods.OpenProcess(NativeMethods.ProcessAccessFlags.DupHandle, false, ps.Id);
                    break;
                   
                    //System.ComponentModel.Win32Exception we = new System.ComponentModel.Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error());
                    //throw new Exception(we.Message);
                }
            }
            
            lstHandles = HandleHelper.GetHandles(selectedProcess);

            HandleLabel.Text = string.Format("Handles count: {0}", lstHandles.Count);
            string strFileName = string.Empty;

            for (int nIndex = 0; nIndex < lstHandles.Count; nIndex++)
            {
                strFileName = HandleHelper.GetFileDetails(selectedProcessHwnd, lstHandles[nIndex]).Name;

                if (strFileName != "")
                {
                    HandlesOfProcessListBox.Items.Add(string.Format("[Handle:{0}] [FileName: {1}]", lstHandles[nIndex].Handle, strFileName));
                }
            }
        }

        private void closeHandleToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.selectedHandleStr != string.Empty)
            {
                Regex pattern = new Regex(@"\[Handle:(?<HandleID>\d+)\]");
                Match matchHandle = pattern.Match(this.selectedHandleStr);
                string handleId = matchHandle.Groups["HandleID"].Value;

                // close handle in other process, which is difficult.
                // perhaps need using code injection, because CloseHandle(IntPtr ipHandle) only close current process's handle
                
                //current we got HandleID, how to know its IntPtr, workaround, prepare a IntPtr list, search the IntPtr based on handleID
                IntPtr currentSelectIntPtr = (IntPtr)(lstHandles.Where(h => h.Handle.ToString() == handleId)).FirstOrDefault().Handle;
                NativeMethods.CloseHandle(currentSelectIntPtr);
            } 
        }

        private void HandlesOfProcessListBox_MouseClick(object sender, MouseEventArgs e)
        {
           
        }

        private void HandlesOfProcessListBox_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                contextMenuStrip1.Show();

                int currentIndex = e.Y / this.HandlesOfProcessListBox.ItemHeight; 
                
                if (HandlesOfProcessListBox.SelectedItem != null && currentIndex != HandlesOfProcessListBox.SelectedIndex)
                {
                    this.HandlesOfProcessListBox.SetSelected(HandlesOfProcessListBox.SelectedIndex, false);
                }

                this.HandlesOfProcessListBox.SetSelected(currentIndex, true);

                this.selectedHandleStr = this.HandlesOfProcessListBox.SelectedItem.ToString();
            }
        }       

    }
}
